package tr.edu.metu.is.mega.client.menu;

import tr.edu.metu.is.mega.client.core.AuthUtils;
import tr.edu.metu.is.mega.client.core.QueryCallback;
import tr.edu.metu.is.mega.client.service.GwtFileService;
import tr.edu.metu.is.mega.client.service.GwtFileServiceAsync;
import tr.edu.metu.is.mega.common.dto.UserDTO;
import tr.edu.metu.is.mega.common.dto.UserRole;

import com.extjs.gxt.ui.client.event.MenuEvent;
import com.extjs.gxt.ui.client.event.SelectionListener;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.menu.Menu;
import com.extjs.gxt.ui.client.widget.menu.MenuBar;
import com.extjs.gxt.ui.client.widget.menu.MenuBarItem;
import com.extjs.gxt.ui.client.widget.menu.MenuItem;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.xml.client.Document;
import com.google.gwt.xml.client.Element;
import com.google.gwt.xml.client.Node;
import com.google.gwt.xml.client.NodeList;
import com.google.gwt.xml.client.XMLParser;

/**
 * Parser to parse menu.xml file.
 */
public class MenuBuilderMenuBar {

    private final MenuBar menuBar;

    private final LayoutContainer container;

    private GwtFileServiceAsync fileService;

    /**
     * Default constructor.
     * 
     * @param menuBar menu bar
     * @param container container
     */
    public MenuBuilderMenuBar(MenuBar menuBar, LayoutContainer container) {
        this.menuBar = menuBar;
        this.container = container;
    }

    /**
     * Builds main menu as a tree.
     */
    public void buildMenu() {
        fileService = GwtFileService.Util.getInstance();
        AuthUtils.getInstance().getCurrentUser(new QueryCallback<UserDTO>() {

            @Override
            public void onQueryResult(UserDTO result) {
                String file = "/menu/mainmenu.xml";
                if (result.getRole() == UserRole.STUDENT) {
                    file = "/menu/studentmenu.xml";
                } else if (result.getRole() != UserRole.ADMIN) {
                    file = "/menu/tamenu.xml";
                }

                fileService.readFile(file, new AsyncCallback<String>() {

                    @Override
                    public void onSuccess(String result) {
                        parseMenuXML(result);
                    }

                    @Override
                    public void onFailure(Throwable caught) {
                        Window.alert("Menu could not be instantiated");
                    }
                });

            }
        });
    }

    /**
     * Parses menu.xml and build menu.
     * 
     * @param text XML string
     */
    private void parseMenuXML(String text) {
        try {
            Document doc = XMLParser.parse(text);
            Element root = doc.getDocumentElement();
            NodeList nodeList = root.getChildNodes();
            for (int i = 0; i < nodeList.getLength(); ++i) {
                Node node = nodeList.item(i);
                if (node.getNodeType() == Node.ELEMENT_NODE) {
                    Element elementMenu = (Element) nodeList.item(i);
                    Menu menu = new Menu();
                    MenuBarItem menuBarItem = new MenuBarItem(elementMenu.getAttribute("label"), menu);
                    menuBar.add(menuBarItem);
                    if (elementMenu.getNodeName().equals("menu")) {
                        loadMenu(menu, elementMenu);
                    }
                }
            }
            doc.getElementsByTagName("menu");
        } catch (Exception ex) {
            Window.alert("Failed to parse menu.xml");
        }
        container.layout(true);
    }

    /**
     * Loads a menu recursively.
     * 
     * @param parentMenu parent menu
     * @param elementMenu menu element
     * @throws Exception exception
     */
    private void loadMenu(Menu parentMenu, Element elementMenu) throws Exception {
        NodeList nodeList = elementMenu.getChildNodes();
        for (int i = 0; i < nodeList.getLength(); ++i) {
            Node node = nodeList.item(i);
            if (node.getNodeType() == Node.ELEMENT_NODE) {
                if (node.getNodeName().equals("menu")) {
                    Element subMenuElement = (Element) node;
                    MenuItem menuItem = new MenuItem(subMenuElement.getAttribute("label"));
                    Menu submenu = new Menu();
                    menuItem.setSubMenu(submenu);
                    loadMenu(submenu, subMenuElement);
                    parentMenu.add(menuItem);
                } else {
                    Element menuItemElement = (Element) node;
                    final String featureIdentifier = menuItemElement.getAttribute("id");
                    MenuItem menuItem = new MenuItem(menuItemElement.getAttribute("label"));
                    menuItem.addSelectionListener(new SelectionListener<MenuEvent>() {

                        @Override
                        public void componentSelected(MenuEvent ce) {
                            MenuActionFactory.doAction(featureIdentifier);
                        }
                    });
                    parentMenu.add(menuItem);
                }
            }
        }
    }

}
